using System;
using System.ComponentModel.Composition;
using System.Threading;
using System.Timers;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
using MefBasic;
using MefBasic.Commans;
using MefBasic.Extensions;
using Microsoft.Practices.Composite.Events;
using Timer = System.Timers.Timer;

namespace MediaAssistant.Controls.WaitScreen
{
    [Export]
    public class WaitScreenPresenter : APresenter<SmallWaitScreenView>
    {
        public static readonly DependencyProperty MessageProperty = DependencyProperty.Register(
            "Message",
            typeof (string),
            typeof (WaitScreenPresenter));

        private readonly Dispatcher _dispatcher;
        private readonly Timer _hideTimer;
        private bool _isLoaded;
        private bool _isShown;
        private Window _waitScreenWindow;

        [ImportingConstructor]
        public WaitScreenPresenter(SmallWaitScreenView view)
            : base(view)
        {
            if (Application.Current != null)
            {
                _dispatcher = Application.Current.Dispatcher;
            }
            _hideTimer = new Timer();
            _hideTimer.Elapsed += HideTimerElapsed;
            _hideTimer.Interval = 300;
            _hideTimer.Enabled = false;

            Enabled = true;

            (view).Loaded += WaitScreenPresenterLoaded;
        }

        [Import]
        public IEventAggregator EventAggreagtor { get; set; }

        public Visibility ProgressBarVisibility
        {
            get { return (Visibility)GetValue(ProgressBarVisibilityProperty); }
            set { SetValue(ProgressBarVisibilityProperty, value); }
        }

        public static readonly DependencyProperty ProgressBarVisibilityProperty =
            DependencyProperty.Register("ProgressBarVisibility", typeof(Visibility), typeof(WaitScreenPresenter), new UIPropertyMetadata(Visibility.Collapsed));



        public int Maximum
        {
            get { return (int)GetValue(MaximumProperty); }
            set { SetValue(MaximumProperty, value); }
        }

        public static readonly DependencyProperty MaximumProperty =
            DependencyProperty.Register("Maximum", typeof(int), typeof(WaitScreenPresenter), new UIPropertyMetadata(0));



        public int Minimum
        {
            get { return (int)GetValue(MinimumProperty); }
            set { SetValue(MinimumProperty, value); }
        }

        public static readonly DependencyProperty MinimumProperty =
            DependencyProperty.Register("Minimum", typeof(int), typeof(WaitScreenPresenter), new UIPropertyMetadata(0));




        public int Value
        {
            get { return (int)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(int), typeof(WaitScreenPresenter), new UIPropertyMetadata(0));



        protected Window WaitScreenWindow
        {
            get
            {
                if (_waitScreenWindow == null)
                {
                    if ((View).Parent != null)
                    {
                        ((Window) (View).Parent).Content = null;
                    }
                    _waitScreenWindow = new Window
                                            {
                                                AllowsTransparency = true,
                                                Content = View,
                                                WindowStyle = WindowStyle.None,
                                                ShowInTaskbar = false,
                                                Background = new SolidColorBrush(Colors.Transparent),
                                                Padding = new Thickness(0),
                                                Margin = new Thickness(0),
                                                WindowState = WindowState.Normal,
                                                WindowStartupLocation = WindowStartupLocation.CenterOwner,
                                                SizeToContent = SizeToContent.WidthAndHeight,
                                            };
                }
                return _waitScreenWindow;
            }
        }


        public bool Enabled { get; set; }

        public string Message
        {
            get { return (string) GetValue(MessageProperty); }
            set { SetValue(MessageProperty, value); }
        }

        public bool DisableParent { get; set; }

        public object Initiator { get; set; }

        private void WaitScreenPresenterLoaded(object sender, RoutedEventArgs e)
        {
            _isLoaded = true;
        }

        public void HideNow()
        {
            HideWaitScreenHandler();
        }

        private void HideTimerElapsed(object sender, ElapsedEventArgs e)
        {
            _hideTimer.Stop();
            if (_dispatcher != null)
                _dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(HideWaitScreenHandler));
        }

        private void HideWaitScreenHandler()
        {
            if ((View).Parent != null)
            {
                ((Window) (View).Parent).Content = null;
            }
            _isShown = false;
            WaitScreenWindow.Close();
            if (DisableParent && Application.Current != null)
            {
                if (Application.Current.MainWindow != null)
                {
                    PublishShellDisabledChanged(false);
                    Application.Current.MainWindow.Focus();
                }
            }
            _waitScreenWindow = null;
        }

        public bool Show()
        {
            ProgressBarVisibility = Visibility.Collapsed;
            return Show("Please Wait...", true);
        }

        public bool Show(string message)
        {
            ProgressBarVisibility = Visibility.Collapsed;
            return Show(message, true);
        }
        public bool Show(int minimum, int maximum, int value)
        {
            Minimum = minimum;
            Maximum = maximum;
            Value = value;
            ProgressBarVisibility = Visibility.Visible;
            return Show(GetProgressMessage(), true);
        }
        public bool Show(int value)
        {
            Value = value;
            ProgressBarVisibility = Visibility.Visible;
            return Show(GetProgressMessage(), true);
        }

        private string GetProgressMessage()
        {
            return string.Format("{0} of {1}",Value,Maximum-Minimum);
        }

        private void ShowWaitScreenHandler()
        {
            if (_isShown)
            {
                _hideTimer.Stop();
                return;
            }
            _isShown = true;
            if (Application.Current.MainWindow is IMainWindow)
                WaitScreenWindow.Owner = Application.Current.MainWindow;
            WaitScreenWindow.Show();
            if (DisableParent)
                PublishShellDisabledChanged(true);
        }

        private void PublishShellDisabledChanged(bool disabled)
        {
            EventAggreagtor.GetEvent<BaseEvent<ShellDisabledChangedEventArgs>>().Publish(new ShellDisabledChangedEventArgs {Sender = this,Disabled = disabled});
        }

        public bool Hide()
        {
            if (_isShown == false)
                return false;
            if (Initiator != null)
                return false;
            _hideTimer.Start();
            return true;
        }

        public bool Show(string message, bool disableParent)
        {
            Message = message;
            if (_isShown)
                return false;
            DisableParent = disableParent;
            if (Enabled && _dispatcher != null)
            {
                _dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(ShowWaitScreenHandler));
                Block(true);
            }
            return true;
        }

        private void Block(bool loaded)
        {
            if (Application.Current == null)
                return;
            while (true)
            {
                Application.Current.DoEvents();
                Thread.Sleep(5);
                if (_isLoaded != loaded)
                    continue;
                break;
            }
        }

        public bool Show(object initiator)
        {
            if (_isShown)
                return false;
            if (Initiator == null)
            {
                Initiator = initiator;
                return Show();
            }
            return false;
        }

        public bool Hide(object initiator)
        {
            if (Initiator != null && Initiator.Equals(initiator))
            {
                Initiator = null;
                return Hide();
            }
            return false;
        }
    }
}